package com.jmb.apiplatform.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.jmb.apiplatform.common.PageResult;
import com.jmb.apiplatform.cores.http.ExecuteHandler;
import com.jmb.apiplatform.cores.parser.Parser;
import com.jmb.apiplatform.exception.BusinessException;
import com.jmb.apiplatform.exception.ValidException;
import com.jmb.apiplatform.mapper.ApiTestAssertMapper;
import com.jmb.apiplatform.mapper.ApiTestCaseMapper;
import com.jmb.apiplatform.mapper.ApiTestCaseRelyDataMapper;
import com.jmb.apiplatform.mapper.ModuleMapper;
import com.jmb.apiplatform.pojo.*;
import com.jmb.apiplatform.service.ApiTestAssertService;
import com.jmb.apiplatform.service.ApiTestCacheParameterService;
import com.jmb.apiplatform.service.ApiTestCaseService;
import com.jmb.apiplatform.service.ApiTestPreCaseService;
import com.jmb.apiplatform.util.ValidUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;


@Slf4j
@Service
public class ApiTestCaseServiceImpl implements ApiTestCaseService {

    @Autowired
    private ApiTestCaseMapper apiTestCaseMapper;
    @Autowired
    private ModuleMapper moduleMapper;
    @Autowired
    private ApiTestAssertMapper apiTestAssertMapper;
    @Autowired
    private ApiTestCaseRelyDataMapper relyDataMapper;
    @Autowired
    private Parser parser;
    @Autowired
    private ApiTestPreCaseService apiTestPreCaseService;
    @Autowired
    private ApiTestAssertService apiTestAssertService;
    @Autowired
    private ApiTestCacheParameterService apiTestCacheParameterService;
    @Autowired
    private ExecuteHandler exceptionHandler;



    @Override
    public ApiTestCaseInfoVO findApiTestByCaseId(Integer preCaseId) throws ValidException {
        if (preCaseId == null){
            throw new ValidException("前置用例编号不能为空");
        }
        return apiTestCaseMapper.selectCaseInfoByCaseId(preCaseId);
    }

    @Override
    public ApiTestCase saveApiTestCase(ApiTestCase apiTestCase) throws ValidException {
        Date date = new Date();
        apiTestCase.setCreatedTime(date);
        apiTestCase.setUpdateTime(date);
        Integer moduleId = apiTestCase.getModuleId();
        Integer projectId = apiTestCase.getProjectId();
        if (moduleId == null || projectId == null) {
            throw new ValidException("模块ID和项目ID不能为空");
        }
        // 获取我们的bodyType,来判读
        Integer bodyType = apiTestCase.getBodyType();
        if (bodyType >= 3 && bodyType !=9) {
            throw new ValidException("bodyType只能为0,1,2,9，参数错误");
        }
        ModuleTO moduleTO = new ModuleTO();
        moduleTO.setModuleId(moduleId);
        moduleTO.setProjectId(projectId);
        // 判断模块&项目是否存在
        if (moduleMapper.selectModelList(moduleTO).isEmpty()){
            log.warn("模块编号/项目编号不存在,moduleId={},projectId={}",moduleId,projectId);
            throw new ValidException("模块编号/项目编号不存在");
        }else {
            // 模块和项目存在插入数据
            apiTestCaseMapper.insertCase(apiTestCase);
        }
        return apiTestCase;
    }



    /**
     * 新增接口测试用例及断言及处理器
     * @throws ValidException 抛出异常
     */


    @Override
    public void saveApiTestCaseInfo(ApiTestCaseTO apiTestCaseTO) throws ValidException {
        // 先插入数据，获取自增id
        Integer caseId = this.saveApiTestCase(apiTestCaseTO).getCaseId();
        // 开始插入前置用例
        List<ApiTestPreCase> preCases = apiTestCaseTO.getPreCases();
        if (preCases != null && !preCases.isEmpty()) {
            for (ApiTestPreCase apiTestPreCase : preCases) {
                Integer preCaseId = apiTestPreCase.getPreCaseId();
                ValidUtil.notNUll(preCaseId, "前置用例编号不能为空");
                ValidUtil.notNUll(this.findApiTestByCaseId(preCaseId), "前置用例编号不存在");
                if (apiTestPreCase.getPreCaseId().equals(caseId)){
                    log.info("传入参数错误，前置用例id等于了自增用例编号");
                    throw  new ValidException("传入参数错误，前置用例id等于了自增用例编号");
                }
                apiTestPreCase.setParentCaseId(caseId);
                apiTestPreCaseService.saveApiTestPreCase(apiTestPreCase);
            }
        }
        // 插入断言表
        List<ApiTestAssert> asserts = apiTestCaseTO.getAsserts();
        if (!asserts.isEmpty()){
            for (ApiTestAssert apiTestAssert : asserts) {
                apiTestAssert.setCaseId(caseId);
                apiTestAssertService.saveApiTestAssert(apiTestAssert);
            }
        }
        // 插入缓存参数表
        List<ApiTestCacheParameter> cacheParameters = apiTestCaseTO.getPostProcessors();
        if (cacheParameters!=null && !cacheParameters.isEmpty()){
            for (ApiTestCacheParameter apiTestCacheParameter : cacheParameters) {
                apiTestCacheParameter.setCaseId(caseId);
                apiTestCacheParameterService.saveApiTestCacheParameter(apiTestCacheParameter);
            }
        }
    }

    @Override
    public PageResult<ApiTestCaseListVO> findApiTestCaseList(ApiTestCaseListTO apiTestCaseListTO) throws ValidException {
        PageHelper.startPage(apiTestCaseListTO.getPageNum(), apiTestCaseListTO.getPageSize());
        ArrayList<ApiTestCaseListVO> caseList= apiTestCaseMapper.selectCaseList(apiTestCaseListTO);
        Page<ApiTestCaseListVO> page = (Page<ApiTestCaseListVO>) caseList;
        return new PageResult<>(page.getTotal(), page.getResult());
    }

    @Override
    public ApiTestCaseInfoVO editApiTestCaseId(Integer caseId) throws ValidException {
        if (caseId == null ){
            throw new ValidException("用例编号不能为空");
        }
         return apiTestCaseMapper.selectCaseInfoByCaseId(caseId);


    }

    @Override
    public void editApiTestCase(ApiTestCaseTO apiTestCaseTO) throws ValidException {
        // 获取caseId
        Integer caseId = apiTestCaseTO.getCaseId();

        ValidUtil.notNUll(caseId, "用例编号错误");

        // 判断bodyType
        Integer bodyType = apiTestCaseTO.getBodyType();
        if (bodyType >= 3 && bodyType != 9) {
            throw new ValidException("bodyType参数错误");
        }

        Date updateTime = new Date();
        apiTestCaseTO.setUpdateTime(updateTime);
        ApiTestCase apiTestCase = new ApiTestCase();
        apiTestCase.setModuleId(apiTestCaseTO.getModuleId());
        apiTestCase.setProjectId(apiTestCaseTO.getProjectId());
        apiTestCase.setCaseId(caseId);
        apiTestCase.setUrl(apiTestCaseTO.getUrl());
        apiTestCase.setMethod(apiTestCaseTO.getMethod());
        apiTestCase.setDescription(apiTestCaseTO.getDescription());
        apiTestCase.setLevel(apiTestCaseTO.getLevel());
        apiTestCase.setDoc(apiTestCaseTO.getDoc());
        apiTestCase.setHeaders(apiTestCaseTO.getHeaders());
        apiTestCase.setParams(apiTestCaseTO.getParams());
        apiTestCase.setFormData(apiTestCaseTO.getFormData());
        apiTestCase.setFormDataEncoded(apiTestCaseTO.getFormDataEncoded());
        apiTestCase.setRaw(apiTestCaseTO.getRaw());
        apiTestCase.setRawType(apiTestCaseTO.getRawType());
        apiTestCase.setBodyType(apiTestCaseTO.getBodyType());
        apiTestCase.setCreater(apiTestCaseTO.getCreater());
        apiTestCase.setUpdateTime(apiTestCaseTO.getUpdateTime());

        String headers = apiTestCase.getHeaders();
        String params = apiTestCase.getParams();
        String formData = apiTestCase.getFormData();
        String formDataEncoded = apiTestCase.getFormDataEncoded();
        String raw = apiTestCase.getRaw();

        // 检查属性中的接口依赖是否包含自身
        this.checkDependencyInCaseProperty(caseId, headers, "headers", false);
        this.checkDependencyInCaseProperty(caseId, params, "params", false);
        this.checkDependencyInCaseProperty(caseId, formData, "formData", false);
        this.checkDependencyInCaseProperty(caseId, formDataEncoded, "formDataEncoded", false);
        this.checkDependencyInCaseProperty(caseId, raw, "raw", false);

        Integer moduleId = apiTestCase.getModuleId();
        Integer projectId = apiTestCase.getProjectId();
        ModuleTO moduleTO = new ModuleTO();
        moduleTO.setModuleId(moduleId);
        moduleTO.setProjectId(projectId);
        //判断入参moduleId是否存在, projectId是否存在
        if (moduleMapper.selectModelList(moduleTO).isEmpty()) {
            log.warn("修改接口测试用例，模块编号/项目编号不存在");
            throw new ValidException("模块编号/项目编号不存在");
        }
        // 修改用例表
        apiTestCaseMapper.updateByCaseId(apiTestCase);
        List<ApiTestAssert> asserts = apiTestCaseTO.getAsserts();
        List<Integer> allAssertId = apiTestAssertMapper.selectAllAssertId(apiTestCaseTO.getCaseId());
        if (asserts != null && !asserts.isEmpty()) {
            for (ApiTestAssert apiTestAssert : asserts) {

                // 检查断言预期结果中接口依赖是否包含自身
                String exceptedResult = apiTestAssert.getExceptedResult();
//                this.checkDependencyInCaseProperty(caseId, exceptedResult, "断言预期结果", false);

                // 修改断言表  修改存在的
                apiTestAssert.setCaseId(apiTestCaseTO.getCaseId());
                apiTestAssertService.editApiTestAssert(apiTestAssert);
                // 新增没有传assertId的
                if (apiTestAssert.getAssertId() == null) {
                    apiTestAssertService.saveApiTestAssert(apiTestAssert);
                } else {
                    // 有就移出此次新增前的id队列
                    for (int i = allAssertId.size() - 1; i >= 0; i--) {
                        if (allAssertId.get(i).equals(apiTestAssert.getAssertId())) {
                            allAssertId.remove(i);
                        }
                    }
                }
            }
            for (Integer assertId : allAssertId) {
                apiTestAssertService.removeAssertById(assertId);
            }
        } else {
            // 移除该接口下所有断言
            apiTestAssertService.removeAssertByCaseId(caseId);
        }

            // 修改前置用例
            List<ApiTestPreCase> preCases = apiTestCaseTO.getPreCases();
        List<Integer> preIdList = apiTestPreCaseService.findApiTestPreCaseById(apiTestCaseTO.getCaseId());
            if (preCases != null && !preCases.isEmpty()) {
                for (ApiTestPreCase apiTestPreCase : preCases) {
                    Integer preCaseId = apiTestPreCase.getPreCaseId();
                    ValidUtil.notNUll(preCaseId, "前置用例编号不能为空");
                ApiTestCaseInfoVO preCaseVO = this.findInterfaceCaseByCaseId(preCaseId);
                ValidUtil.notNUll(preCaseVO, "前置用例编号不存在");

                    // 检查前置用例属性中的接口依赖是否包含自身
                String preHeaders = preCaseVO.getHeaders();
                String preParams = preCaseVO.getParams();
                String preFormData = preCaseVO.getFormData();
                String preFormDataEncoded = preCaseVO.getFormDataEncoded();
                String preRaw = preCaseVO.getRaw();
                List<ApiTestAssertVO> preCaseAsserts = preCaseVO.getAsserts();
                this.checkDependencyInCaseProperty(caseId, preHeaders, String.format("[%s]headers", preCaseId), true);
                this.checkDependencyInCaseProperty(caseId, preParams, String.format("[%s]params", preCaseId), true);
                this.checkDependencyInCaseProperty(caseId, preFormData, String.format("[%s]formData", preCaseId), true);
                this.checkDependencyInCaseProperty(caseId, preFormDataEncoded, String.format("[%s]formDataEncoded", preCaseId), true);
                this.checkDependencyInCaseProperty(caseId, preRaw, String.format("[%s]raw", preCaseId), true);
                for (ApiTestAssertVO interfaceAssert : preCaseAsserts) {
                    String exceptedResult = interfaceAssert.getExceptedResult();
                    this.checkDependencyInCaseProperty(caseId, exceptedResult, String.format("[%s]断言预期结果", preCaseId), true);
                }

                    apiTestPreCase.setParentCaseId(apiTestCaseTO.getCaseId());
                    // 1.修改已存在的
                    apiTestPreCaseService.editApiTestPreCase(apiTestPreCase);
                    // 2.新增没有自增Id的
                    if (apiTestPreCase.getId() == null) {
                        apiTestPreCaseService.saveApiTestPreCase(apiTestPreCase);
                } else {
                    // 3.有就移出此次新增前的id队列
                    for (int i = preIdList.size() - 1; i >= 0; i--) {
                        if (preIdList.get(i).equals(apiTestPreCase.getId())) {
                            preIdList.remove(i);
                        }
                    }
                }
                    }
            for (Integer id : preIdList) {
                // 移除该用例下莫个用例
                apiTestPreCaseService.removeApiTestPreCase(id);
            }
        } else {
            // 移除该用例下所有的前置用例
            apiTestPreCaseService.removeApiTestPreCaseByCaseId(caseId);
        }

                    // 修改处理器
                    List<ApiTestCacheParameter> postProcessors = apiTestCaseTO.getPostProcessors();
        List<Integer> postProcessorIdList = apiTestCacheParameterService.findCacheParameterByCaseId(apiTestCaseTO.getCaseId());
                    if (postProcessors != null && !postProcessors.isEmpty()) {
                        for (ApiTestCacheParameter cacheParameter : postProcessors) {
                            cacheParameter.setCaseId(apiTestCase.getCaseId());
                            // 1.修改已存在的
                apiTestCacheParameterService.editApiTestCacheParameter(cacheParameter);
                            // 2.新增没有postProcessorId的
                            if (cacheParameter.getProcessorId() == null) {
                                apiTestCacheParameterService.saveApiTestCacheParameter(cacheParameter);
                            } else {
                                // 3.有就移出此次新增前的id队列
                    for (int i = postProcessorIdList.size() - 1; i >= 0; i--) {
                        if (postProcessorIdList.get(i).equals(cacheParameter.getProcessorId())) {
                            postProcessorIdList.remove(i);
                        }
                    }
                            }
                        }
            for (Integer postProcessorId : postProcessorIdList) {
                apiTestCacheParameterService.removeCacheParameterById(postProcessorId);
            }
                    } else {
                        // 移除该用例下所有的处理器
            apiTestCacheParameterService.removeCacheParameterByCaseId(caseId);
                    }

                }

    @Override
    public ApiTestCaseInfoVO findInterfaceCaseByCaseId(Integer caseId) {
        return apiTestCaseMapper.selectCaseInfoByCaseId(caseId);
    }

    @Override
    public void removeApiTestCase(Integer caseId) throws ValidException {
        boolean inIfRelyData = true;
        boolean inCaseRef = true;
        String errorMsg = "";

        // 检查是否存在于t_interface_case_rely_data
        ApiTestCaseRelyDataTO relyDataTO = new ApiTestCaseRelyDataTO();
        relyDataTO.setRelyCaseId(caseId);

        // 检查是否存在于t_interface_suite_case_ref
//        InterfaceSuiteCaseRefDTO interfaceSuiteCaseRefDTO = new InterfaceSuiteCaseRefDTO();
//        interfaceSuiteCaseRefDTO.setCaseId(interfaceCaseId);

        if (relyDataMapper.selectRelyDataList(relyDataTO).isEmpty()) {
            inIfRelyData = false;
        } else {
            log.warn("删除接口测试用例，该用例已存在与数据中心-接口依赖，interfaceCaseId={}", caseId);
            errorMsg = errorMsg + "该用例已存在于接口依赖";
        }
        // 检查是否存在于t_interface_suite_case_ref
//        if (interfaceSuiteCaseRefMapper.selectSuiteCaseList(interfaceSuiteCaseRefDTO).isEmpty()) {
//            inCaseRef = false;
//        } else {
//            LOG.warn("删除接口测试用例，该用例已存在与接口测试-测试套件，interfaceCaseId={}", interfaceCaseId);
//            errorMsg = errorMsg + "该用例已存在于测试套件";
//        }
        if (!inIfRelyData) {
            apiTestCaseMapper.removeApiTestCase(caseId);
            // 删除与之相关的断言
            apiTestAssertService.removeAssertByCaseId(caseId);
            // 删除与之相关的处理器
            apiTestCacheParameterService.removeCacheParameterByCaseId(caseId);
            // 删除与之相关的前置用例
            apiTestPreCaseService.removeApiTestPreCaseByCaseId(caseId);
        } else {
            throw new ValidException(errorMsg);
        }
    }


    /**
     * 执行接口测试用例
     * @param executeInterfaceCaseParam 执行接口测试用例参数
     * @return 日志编号
     * @throws ValidException 执行异常
     */
    @Override
    public Integer executeInterfaceCase(ExecuteInterfaceCaseParam executeInterfaceCaseParam) throws  BusinessException {

        return exceptionHandler.executeInterfaceCase(executeInterfaceCaseParam);
    }


    /**
     * 检查属性中的接口依赖是否包含自身
     * @param caseId 用例编号
     * @param property 域，如headers、params、formdata、formdataencoded、raw
     * @param propertyDesc 描述
     * @param isPreCase 是否为前置用例
     * @throws ValidException validException
     */

    private void checkDependencyInCaseProperty(Integer caseId, String property, String propertyDesc, boolean isPreCase) throws ValidException {
        ArrayList<String> dependencyOfHeaders = parser.extractDependencyName(property);
        for (String s : dependencyOfHeaders) {

            // 检查接口依赖
            ApiTestCaseRelyDataVO interfaceCaseRelyDataVO = relyDataMapper.selectRelyDataByName(s);
            if (null != interfaceCaseRelyDataVO) {
                int relyCaseId = interfaceCaseRelyDataVO.getRelyCaseId();
                if (caseId == relyCaseId) {
                    if (!isPreCase) {
                        throw new ValidException(String.format("当前用例%s中的依赖不能引用自身", propertyDesc));
                    } else {
                        throw new ValidException(String.format("当前用例的前置用例%s中的依赖不能引用自身", propertyDesc));
                    }
                }
            }

        }
    }
}
